var count = 30;

// Does not throw an error
if (true) {
	let count
	console.log("count",count);
    count = 40;
    console.log("count",count);

    // more code
}



//var message = "Hello!";
//let age = 25;

// Each of these would throw an error.
const message = "Goodbye!";
const age = 30;


if (true) {
    //console.log(typeof value);  // ReferenceError!
    //let value = "blue";
}

// throws an error after one iteration

/*var funcs = [];

for (const i = 0; i < 10; i++) {
    funcs.push(function() {
        console.log(i);
    });
}

var funcs = [],
    object = {
        a: true,
        b: true,
        c: true
    };



// doesn't cause an error
for (const key in object) {
    funcs.push(function() {
        console.log(key);
    });
}

funcs.forEach(function(func) {
    func();     // outputs "a", then "b", then "c"
});*/



var text = "𠮷a";

console.log(text.charCodeAt(0));    // 55362
console.log(text.charCodeAt(1));    // 57271
console.log(text.charCodeAt(2));    // 97

console.log(text.codePointAt(0));   // 134071
console.log(text.codePointAt(1));   // 57271
console.log(text.codePointAt(2));   // 97


function is32Bit(c) {
    return c.codePointAt(0) > 0xFFFF;
}

console.log(is32Bit("𠮷"));         // true
console.log(is32Bit("a"));          // false

console.log(String.fromCodePoint(134071));

var text = "𠮷";

console.log(text.length);           // 2
console.log(/^.$/.test(text));      // false
console.log(/^.$/u.test(text));     // true


function codePointLength(text) {
    var result = text.match(/[\s\S]/gu);
    return result ? result.length : 0;
}

console.log(codePointLength("abc"));    // 3
console.log(codePointLength("𠮷bc"));   // 3


var msg = "Hello world!";

console.log(msg.startsWith("Hello"));       // true
console.log(msg.endsWith("!"));             // true
console.log(msg.includes("o"));             // true

console.log(msg.startsWith("o"));           // false
console.log(msg.endsWith("world!"));        // true
console.log(msg.includes("x"));             // false

console.log(msg.startsWith("o", 4));        // true
console.log(msg.endsWith("o", 8));          // true
console.log(msg.includes("o", 8));          // false


var text = "hello1 hello2 hello3",
    pattern = /hello\d\s?/,
    result = pattern.exec(text),
    globalPattern = /hello\d\s?/g,
    globalResult = globalPattern.exec(text),
    stickyPattern = /hello\d\s?/y,
    stickyResult = stickyPattern.exec(text);

console.log(result[0]);         // "hello1 "
console.log(globalResult[0]);   // "hello1 "
console.log(stickyResult[0]);   // "hello1 "

pattern.lastIndex = 1;
globalPattern.lastIndex = 1;
stickyPattern.lastIndex = 1;

result = pattern.exec(text);
globalResult = globalPattern.exec(text);
stickyResult = stickyPattern.exec(text);

console.log(result[0]);         // "hello1 "
console.log(globalResult[0]);   // "hello2 "
//console.log(stickyResult[0]);   // Error! stickyResult is null

var pattern = /hello\d/y;

console.log(pattern.sticky);    // true

var re1 = /ab/i,

    // throws an error in ES5, okay in ES6
    re2 = new RegExp(re1, "g");


console.log(re1.toString());            // "/ab/i"
console.log(re2.toString());            // "/ab/g"

console.log(re1.test("ab"));            // true
console.log(re2.test("ab"));            // true

console.log(re1.test("AB"));            // true
console.log(re2.test("AB"));            // false

var re = /ab/g;

console.log(re.source);     // "ab"
console.log(re.flags);      // "g"

let message3 = `Multiline
string`;

console.log(message3);           // "Multiline
                                //  string"
console.log(message3.length);    // 16


let count2 = 10,
    price = 0.25,
    message4 = `${count} items cost $${(count2 * price).toFixed(2)}.`;

console.log(message4);       // "10 items cost $2.50."

function passthru(literals, ...substitutions) {
    let result = "";

    // run the loop only for the substitution count
    for (let i = 0; i < substitutions.length; i++) {
        result += literals[i];
        result += substitutions[i];
    }

    // add the last literal
    result += literals[literals.length - 1];

    return result;
}

let count5 = 10,
    price5 = 0.25,
    message5 = passthru`${count5} items cost $${(count5 * price5).toFixed(2)}.`;

console.log(message5);       // "10 items cost $2.50."


var xx=xx;
console.log("Xx=",xx);

/*function f() { console.log('I am outside!'); }

(function () {
  if (false) {
    // 重复声明一次函数f
    function f() { console.log('I am inside!'); }
  }

  f();
}());*/

let [a2, b2, c2] = [1, 2, 3];
console.log(a2,b2,c2);

function f() {
  console.log('aaa');
  return 22
}

let [x4 = f()] = [1];
console.log(x4);


// not in strict mode
function mixArgs(first, second = "b") {
    console.log(arguments.length);
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
    first = "c";
    second = "d"
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
}

mixArgs("a");

function getValue(value) {
    return value + 5;
}

function add(first, second = getValue(first)) {
    return first + second;
}

console.log(add(1, 1));     // 2
console.log(add(1));        // 7

function pick(object, ...keys) {
    let result = Object.create(null);

    for (let i = 0, len = keys.length; i < len; i++) {
        result[keys[i]] = object[keys[i]];
    }

    return result;
}

console.log(pick.length);

var pickGlobal = new Function("...args", "return this");

console.log(pickGlobal()===global);   // 1

var doSomething = function doSomethingElse() {
    // ...
};

var person = {
    get firstName() {
        return "Nicholas"
    },
    sayName: function() {
        console.log(this.name);
    }
}

console.log(doSomething.name);      // "doSomethingElse"
console.log(person.sayName.name);   // "sayName"

var descriptor = Object.getOwnPropertyDescriptor(person, "firstName");
console.log(descriptor.get.name); // "get firstName"


console.log(doSomething.bind().name);   // "bound doSomething"

console.log((new Function()).name);     // "anonymous"


function Person(name) {
	console.log(new.target,this);
    if (new.target === Person) {
        this.name = name;   // using new
    } else {
        throw new Error("You must use new with Person.")
    }
}

function AnotherPerson(name) {
    Person.call(this, name);
}

var person = new Person("Nicholas");
//var p2 = Person.call(person,"test");
//console.log(p2);
//var anotherPerson = new AnotherPerson("Nicholas");  // error!

var reflect = value => value;
console.log(reflect.name);

var doNothing = ()=>{};
//console.log(new doNothing);
var getTempItem = id => ({ id: id, name: "Temp" });

let person5 = ((name) => {

    return {
        getName: function() {
            return name;
        }
    };

})("Nicholas");

console.log(person5.getName());      // "Nicholas"

console.log(+0 == -0);              // true
console.log(+0 === -0);             // true
console.log(Object.is(+0, -0));     // false

console.log(NaN == NaN);            // false
console.log(NaN === NaN);           // false
console.log(Object.is(NaN, NaN));   // true

console.log(5 == 5);                // true
console.log(5 == "5");              // true
console.log(5 === 5);               // true
console.log(5 === "5");             // false
console.log(Object.is(5, 5));       // true
console.log(Object.is(5, "5"));     // false


var receiver = {},
    supplier = {
        get name() {
            return "file.js"
        }
    };

Object.assign(receiver, supplier);

var descriptor = Object.getOwnPropertyDescriptor(receiver, "name");

console.log(descriptor.value);      // "file.js"
console.log(descriptor.get);        // undefined


let person6 = {
	"p1":6,
    getGreeting() {
        return "Hello"+this.p1;
    }
};

let person7 = {
	"p1":7,
    getGreeting() {
        return "Hello77777";
    }
};

// prototype is person
let friend = {
	"p1":123,
    getGreeting() {
        return super.getGreeting() + ", hi!,"+this.p1;
    }
};
console.log(friend.__proto__)
//Object.setPrototypeOf(friend, person6);
friend.__proto__ = person6;
console.log(friend.__proto__)

// prototype is friend
//let relative = Object.create(friend);

//console.log(person6.getGreeting());                  // "Hello"
//console.log(friend.getGreeting());                  // "Hello, hi!"
//console.log(relative.getGreeting());                // "Hello, hi!"

//Object.setPrototypeOf(friend, person7);
//console.log(person6.getGreeting());                  // "Hello"
//console.log(friend.getGreeting());                  // "Hello, hi!"

var testFunc = friend.getGreeting.bind(person7);
console.log(friend.getGreeting()); 
console.log(testFunc()); 


function f(x = 1, y) {
  return [x, y];
}

f() // [1, undefined]
f(2) // [2, undefined])
//f(, 1) // 报错
f(undefined, 1) // [1, 1]

var x = 1;
function foo(x, y = function() { x = 2; }) {
  var x = 3;
  y();
  console.log(x,arguments[0]);
}

foo(5) // 3
console.log(x) // 1


function MyObject() {
    
}

Object.defineProperty(MyObject, Symbol.hasInstance, {
    value: function(v) {
        return false;
    }
});


/*MyObject[Symbol.hasInstance] = function(){//non-writable
	console.log("2222");
	return false;
}*/

let obj = new MyObject();

console.log(obj,MyObject,obj instanceof MyObject);       // false


function dedupe(array) {
  return Array.from(new Set(array));
}

dedupe([1, 1, 2, 3]) // [1, 2, 3]

var objp = new Proxy({}, {
  get: function (target, key, receiver) {
    console.log(`getting ${key}!`);
    return Reflect.get(target, key, receiver);
  },
  set: function (target, key, value, receiver) {
    console.log(`setting ${key}!`);
    return Reflect.set(target, key, value, receiver);
  }
});

objp.count = 1
//  setting count!
++objp.count

var handler = {
  get: function(target, name) {
    if (name === 'prototype') {
      return Object.prototype;
    }
    return 'Hello, ' + name;
  },

  apply: function(target, thisBinding, args) {
    return args[0];
  },

  construct: function(target, args) {
    return {value: args[1]};
  }
};

var fproxy = new Proxy(function(x, y) {
  return x + y;
}, handler);

console.log(fproxy(1, 2)) // 1

console.log(new fproxy(1,2)) // {value: 2}
fproxy.prototype === Object.prototype // true

console.log(fproxy.foo) // "Hello, foo"


var pipe = (function () {
  return function (value) {
    var funcStack = [];
    var oproxy = new Proxy({} , {
      get : function (pipeObject, fnName) {
        if (fnName === 'get') {
        	
          return funcStack.reduce(function (val, fn) {
            return fn(val);
          },value);
        }
        funcStack.push(global[fnName]);
        return oproxy;
      }
    });

    return oproxy;
  }
}());

global.double = n => n * 2;
global.pow    = n => n * n;
global.reverseInt = n => n.toString().split("").reverse().join("") | 0;

console.log(pipe(3).double.pow.reverseInt.get); // 63



class RangeIterator {
  constructor(start, stop) {
    this.value = start;
    this.stop = stop;
  }

  [Symbol.iterator]() { return this; }

  next() {
    var value = this.value;
    if (value < this.stop) {
      this.value++;
      return {done: false, value: value};
    }
    return {done: true, value: undefined};
  }
}

function range(start, stop) {
  return new RangeIterator(start, stop);
}

for (var value of range(0, 3)) {
  console.log(value);
}

let iterable = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3,
  [Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
  console.log(item); // 'a', 'b', 'c'
}

function *createIterator(items) {
    for (let i = 0; i < items.length; i++) {
        yield items[i];
    }
}

let iterator = createIterator([1, 2, 3]);

console.log(iterator.next());           // "{ value: 1, done: false }"
console.log(iterator.next());           // "{ value: 2, done: false }"
console.log(iterator.next());           // "{ value: 3, done: false }"
console.log(iterator.next());           // "{ value: undefined, done: true }"

// for all further calls
console.log(iterator.next());           // "{ value: undefined, done: true }"

var o = {

    *createIterator(items) {
        for (let i = 0; i < items.length; i++) {
            yield items[i];
        }
    }
};

let iterator2 = o.createIterator([1, 2, 3]);
console.log(Object.getOwnPropertyDescriptor(iterator2));


let objIter = {
	items:[],
	*[Symbol.iterator](){
		for(let item of this.items){
			yield item;
		}
	}

}

objIter.items.push(...[1,2,3,4,5]);
for(let i of objIter){
	console.log(i);
}

function *createIterator() {
    let first = yield 1;
    let second = yield first + 2;       // yield 4 + 2, then throw
    yield second + 3;                   // never is executed
}

let iterator3 = createIterator();

console.log(iterator3.next());                   // "{ value: 1, done: false }"
console.log(iterator3.next(4));                  // "{ value: 6, done: false }"
//console.log(iterator3.throw(new Error("Boom"))); // error thrown from generator


function *createIterator() {
    let first = yield 1;
    let second;

    try {
        second = yield first + 2;       // yield 4 + 2, then throw
    } catch (ex) {
        second = 6;                     // on error, assign a different value
    }
    yield second + 3;
}

let iterator4 = createIterator();

console.log(iterator4.next());                   // "{ value: 1, done: false }"
console.log(iterator4.next(4));                  // "{ value: 6, done: false }"
//console.log(iterator4.throw(new Error("Boom"))); // "{ value: 9, done: false }"
console.log(iterator4.next());                   // "{ value: undefined, done:true }"


function *createIterator() {
    yield 1;
    return "dddd";
    yield 2;
    yield 3;
}

let iterator5 = createIterator();

console.log(iterator5.next());           // "{ value: 1, done: false }"
console.log(iterator5.next());           // "{ value: undefined, done: true }"


function *createNumberIterator() {
    yield 1;
    yield 2;
    return 3;
}

function *createRepeatingIterator(count) {
    for (let i=0; i < count; i++) {
        yield "repeat";
    }
}

function *createCombinedIterator() {
    let result = yield *createNumberIterator();
    yield *createRepeatingIterator(result);
}

var iterator6 = createCombinedIterator();

console.log(iterator6.next());           // "{ value: 1, done: false }"
console.log(iterator6.next());           // "{ value: 2, done: false }"
console.log(iterator6.next());           // "{ value: "repeat", done: false }"
console.log(iterator6.next());           // "{ value: "repeat", done: false }"
console.log(iterator6.next());           // "{ value: "repeat", done: false }"
console.log(iterator6.next());           // "{ value: undefined, done: true }"


function run(taskDef) {

    // create the iterator, make available elsewhere
    let task = taskDef();

    // start the task
    let result = task.next();

    // recursive function to keep calling next()
    function step() {

        // if there's more to do
        if (!result.done) {
            if (typeof result.value === "function") {
                result.value(function(err, data) {
                    if (err) {
                        result = task.throw(err);
                        return;
                    }

                    result = task.next(data);
                    step();
                });
            } else {
                result = task.next(result.value);
                step();
            }

        }
    }

    // start the process
    step();

}

run(function*() {
    let value = yield 1;
    console.log(value);         // 1

    value = yield value + 3;
    console.log(value);         // 4
});


var fetch = require('node-fetch');

function* gen(){
  var url = 'https://api.github.com/users/github';
  var result = yield fetch(url);
  console.log(result.bio);
}

/*var g = gen();
var result = g.next();

result.value.then(function(data){
  return data.json();
}).then(function(data){
  g.next(data);
});*/

var thunkify = require('thunkify');
var fs = require('fs');

var read = thunkify(fs.readFile);
read('package.json')(function(err, str){
  console.log("OK........");
});

function tt(a,b,c,cb){
    console.log(a,b,c);
    cb();
}

var ttt = thunkify(tt);
ttt(1,2,3)(function(){
    console.log("123.....OK");
})

var readFile = function (fileName){
  return new Promise(function (resolve, reject){
    fs.readFile(fileName, function(error, data){
      if (error) return reject(error);
      resolve(data);
    });
  });
};

var gen2 = function* () {
  var f1 = yield readFile('v8.js');
  var f2 = yield readFile('package.json');
  console.log(f1.toString());
  console.log(f2.toString());
};

var co = require('co');
co(gen2).then(function (){
  console.log('Generator 函数执行完成');
});

function run2(gen){
  var g = gen();

  function next(data){
    var result = g.next(data);
    if (result.done) return result.value;
    result.value.then(function(data){
      next(data);
    });
  }

  next();
}

run2(gen2);


function timeout(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}

asyncPrint('hello world', 50);

function spawn(genF){
    return new Promise(function(resolve,reject){
        var gen = genF();
        function step(nextF){
            try{
                var next = nextF();
            }
            catch(e){
                reject(e);
            }

            if(next.done){
                return resolve(next.value);
            }

            Promise.resolve(next.value).then(function(v){
                step(function(){return gen.next(v)});
            },function(e){
                step(function() { return gen.throw(e); });
            })
        }

        step(function(){return gen.next(undefined)});
    })
}

let MyClassOut = class MyClass{
    constructor(test){
        MyClass.test = test;
    }
}

var m = new MyClassOut("dddddddddddddd");
console.log(MyClassOut.test);



let rejected;

process.on("rejectionHandled", function(promise) {
    console.log(rejected === promise);              // true
});

rejected = Promise.reject(new Error("Explosion!"));

// wait to add the rejection handler
setTimeout(function() {
    rejected.catch(function(value) {
        console.log(value.message);     // "Explosion!"
    });
}, 1000);
